import { Command } from 'commander';
import inquirer from 'inquirer';
import { api } from '../services/api';
import { config } from '../services/config';
import { logger } from '../utils/logger';
import { createTable, formatDate } from '../utils/table';
import { requireAuth, validateProjectName } from '../utils/validation';
import { CLIError } from '../types';

export function projectCommands(program: Command): void {
  const projectCmd = program
    .command('project')
    .description('Project management commands');

  projectCmd
    .command('create <name>')
    .description('Create a new project')
    .option('-d, --description <description>', 'Project description')
    .action(async (name: string, options) => {
      try {
        requireAuth();

        if (!validateProjectName(name)) {
          throw new CLIError('Invalid project name. Use only letters, numbers, hyphens, and underscores.');
        }

        let { description } = options;

        if (!description) {
          const answers = await inquirer.prompt([
            {
              type: 'input',
              name: 'description',
              message: 'Project description (optional):',
            }
          ]);
          description = answers.description;
        }

        const spinner = logger.spinner('Creating project...');
        try {
          const project = await api.createProject(name, description);
          spinner.succeed();
          
          logger.success(`Project "${project.name}" created successfully`);
          logger.info(`Project ID: ${project.id}`);
          
          const useProject = await inquirer.prompt([
            {
              type: 'confirm',
              name: 'use',
              message: 'Set as current project?',
              default: true
            }
          ]);

          if (useProject.use) {
            config.setCurrentProject(project.id);
            logger.success(`Switched to project "${project.name}"`);
          }
        } catch (error) {
          spinner.fail();
          throw error;
        }
      } catch (error) {
        if (error instanceof CLIError) {
          throw error;
        }
        throw new CLIError('Failed to create project');
      }
    });

  projectCmd
    .command('list')
    .description('List all projects')
    .action(async () => {
      try {
        requireAuth();

        const spinner = logger.spinner('Fetching projects...');
        try {
          const projects = await api.getProjects();
          spinner.succeed();

          if (projects.length === 0) {
            logger.info('No projects found. Create one with "cm project create <name>"');
            return;
          }

          const currentProject = config.getCurrentProject();
          const headers = ['', 'Name', 'Description', 'Owner', 'Environments', 'Created'];
          const rows = projects.map(project => [
            project.id === currentProject ? '*' : ' ',
            project.name,
            project.description || '-',
            project.owner,
            project.environments?.length.toString() || '0',
            formatDate(project.createdAt)
          ]);

          logger.log('\n' + createTable(headers, rows));
          logger.info('\n* = current project');
        } catch (error) {
          spinner.fail();
          throw error;
        }
      } catch (error) {
        if (error instanceof CLIError) {
          throw error;
        }
        throw new CLIError('Failed to list projects');
      }
    });

  projectCmd
    .command('use <name>')
    .description('Switch to a project')
    .action(async (name: string) => {
      try {
        requireAuth();

        const spinner = logger.spinner('Fetching projects...');
        try {
          const projects = await api.getProjects();
          spinner.succeed();

          const project = projects.find(p => p.name === name || p.id === name);
          if (!project) {
            throw new CLIError(`Project "${name}" not found`);
          }

          config.setCurrentProject(project.id);
          logger.success(`Switched to project "${project.name}"`);
          
          if (project.environments && project.environments.length > 0) {
            const defaultEnv = project.environments.find(e => e.name === 'dev') || project.environments[0];
            config.setCurrentEnvironment(defaultEnv.name);
            logger.info(`Default environment set to "${defaultEnv.name}"`);
          }
        } catch (error) {
          if (error instanceof CLIError) {
            throw error;
          }
          spinner.fail();
          throw new CLIError('Failed to switch project');
        }
      } catch (error) {
        if (error instanceof CLIError) {
          throw error;
        }
        throw new CLIError('Failed to switch project');
      }
    });

  projectCmd
    .command('info')
    .description('Show current project information')
    .action(async () => {
      try {
        requireAuth();
        const projectId = config.getCurrentProject();
        
        if (!projectId) {
          logger.error('No project selected. Use "cm project use <name>" to select a project.');
          return;
        }

        const spinner = logger.spinner('Fetching project information...');
        try {
          const project = await api.getProject(projectId);
          spinner.succeed();

          logger.log(`\nProject Information:`);
          logger.log(`Name: ${project.name}`);
          logger.log(`Description: ${project.description || 'No description'}`);
          logger.log(`Owner: ${project.owner}`);
          logger.log(`Created: ${formatDate(project.createdAt)}`);
          logger.log(`Updated: ${formatDate(project.updatedAt)}`);
          
          if (project.environments && project.environments.length > 0) {
            logger.log(`\nEnvironments:`);
            project.environments.forEach(env => {
              const current = env.name === config.getCurrentEnvironment() ? ' (current)' : '';
              logger.log(`  • ${env.name} (${env.type})${current}`);
            });
          }

          if (project.modules && project.modules.length > 0) {
            logger.log(`\nModules: ${project.modules.length} installed`);
          }
        } catch (error) {
          spinner.fail();
          throw error;
        }
      } catch (error) {
        if (error instanceof CLIError) {
          throw error;
        }
        throw new CLIError('Failed to get project information');
      }
    });
}